package org.ax.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.extension.plugins.IllegalSQLInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import com.zaxxer.hikari.HikariDataSource;
import lombok.Data;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.management.CacheManagerMBean;
import org.apache.ibatis.session.AutoMappingBehavior;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.crypto.hash.Hash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.ax.data.Result;
import org.ax.util.RedisUtil;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.cache.ehcache.EhCacheManagerFactoryBean;
import org.springframework.context.annotation.*;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import redis.clients.jedis.JedisPoolConfig;

import javax.annotation.PostConstruct;
import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * 编程人:赵浩鑫
 * 时间:2021-01-19-14:21
 * 设置服务时区,作用域mysql:set global time_zone ='+8:00';
*/
@Configuration
@MapperScan("org.ax.mapper")
@ComponentScan(value = {"org.ax.service","org.ax.websocket","org.ax.acrSoft.service"})
@EnableTransactionManagement

@Data
@Slf4j
public class SpringConfig {
    @Value("#{propertiesFactoryBean['spring.datasource.password']}")
    private String password;
    @Value("#{propertiesFactoryBean['spring.datasource.url']}")
    private String url;
    @Value("#{propertiesFactoryBean['spring.datasource.username']}")
    private String username;
    @Value("#{propertiesFactoryBean['spring.datasource.driver']}")
//    @Value("${spring.datasource.driver}")
    private String driver;
////
//    @Bean
////    @Value("#{propertiesFactoryBean['spring.datasource']}")
////    @ConfigurationProperties("spring.datasource")//和配置文件中以这个前缀字段和属性进行映射
//    public DataSource dataSource() throws SQLException {
//        DruidDataSource dataSource=new DruidDataSource();
//        dataSource.setUsername(username);
//        dataSource.setPassword(password);
//        dataSource.setDriverClassName(driver);
//        dataSource.setUrl(url);
//        //开启监控统计功能和防火墙
//        dataSource.setFilters("stat,wall");
//        return dataSource;
//    }
//    @Bean("druidServlet")
//    public ServletRegistrationBean servletRegistrationBean(){
//        ServletRegistrationBean servletRegistrationBean=new ServletRegistrationBean(new StatViewServlet(),"/druid/*");
//        //配置加载参数
//        servletRegistrationBean.addInitParameter("loginUsername","admin");
//        servletRegistrationBean.addInitParameter("loginPassword", "123456");
//        return servletRegistrationBean;
//    }
//    @Bean("druidFilter")
//    public FilterRegistrationBean filterRegistrationBean(){
//        FilterRegistrationBean filterRegistrationBean=new FilterRegistrationBean(new WebStatFilter());
//        filterRegistrationBean.setUrlPatterns(Arrays.asList("/*"));
//        filterRegistrationBean.addInitParameter("exclusions","*.js,*.gif,*.jpg, *.png,*.css,*.ico,/druid/");
//        return filterRegistrationBean;
//    }
    @PostConstruct
    @Bean
    public PropertiesFactoryBean propertiesFactoryBean(){
        PropertiesFactoryBean propertiesFactoryBean=new PropertiesFactoryBean();
        propertiesFactoryBean.setLocation(patternResolver().getResource("classpath:ssm.properties"));
        return propertiesFactoryBean;
    }
    @Bean
    public DataSource dataSource(){
        HikariDataSource dataSource=new HikariDataSource();
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        dataSource.setDriverClassName(driver);
        dataSource.setJdbcUrl(url);
        return dataSource;
    }
    @Bean
    public MybatisConfiguration mybatisConfiguration(){
        MybatisConfiguration c=new MybatisConfiguration();
        c.setMapUnderscoreToCamelCase(true);
        c.setAutoMappingBehavior(AutoMappingBehavior.FULL);
        c.setUseGeneratedKeys(true);
        c.addMappers("org.ax.mapper");
        return c;
    }
    @Bean
    public PathMatchingResourcePatternResolver patternResolver(){
        return new PathMatchingResourcePatternResolver();
    }
    @SneakyThrows
    @Bean
    public MybatisSqlSessionFactoryBean mybatisSqlSessionFactoryBean(){
        MybatisSqlSessionFactoryBean s=new MybatisSqlSessionFactoryBean();
        s.setDataSource(dataSource());
        s.setConfiguration(mybatisConfiguration());
        s.setTypeAliasesPackage("org.ax.bean");
        s.setPlugins(new PaginationInterceptor());
//        s.setMapperLocations(patternResolver().getResources("classpath:mapper/*.xml"));
        return s;
    }
    @SneakyThrows
    @Bean
    public DataSourceTransactionManager dataSourceTransactionManager(){
        DataSourceTransactionManager dataSourceTransactionManager=new DataSourceTransactionManager();
        dataSourceTransactionManager.setDataSource(dataSource());
        return dataSourceTransactionManager;
    }
    @Bean
    public Result result(){
        return new Result();
    }

    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(){
        ShiroFilterFactoryBean s=new ShiroFilterFactoryBean();
        s.setSecurityManager(defaultWebSecurityManager());
        Map<String,String> filterMap=new HashMap<String,String>();
        /**
         * Shiro内置过滤器,可以实现权限相关的拦截器
         *   常用的过滤器:
         *      anon:无需验证(登录)可以访问
         *      authc:必须认证才可以访问
         *      user:如果使用rememberMe的功能可以直接访问
         *      perms:该资源必须得到资源权限才可以访问
         *      roles:该资源必须得到角色的权限才可以访问
         */
        filterMap.put("/sys/login","anon");
        filterMap.put("/webjars/**","anon");
        filterMap.put("/sys/email","anon");
        filterMap.put("/layuiadmin/**","anon");
        filterMap.put("/websocket/**","anon");
        filterMap.put("/druid/**","anon");
        filterMap.put("/compareFaces","anon");
        filterMap.put("/**","authc");
        filterMap.put("/logout","logout");
//        filterMap.put("/menu","perms[execute]");
//        s.setFilterChainDefinitionMap();
        s.setFilterChainDefinitionMap(filterMap);
        s.setLoginUrl("/");
        s.setUnauthorizedUrl("/unthor");
        return s;
    }



    @Bean
    public DefaultWebSecurityManager defaultWebSecurityManager(){
        DefaultWebSecurityManager d=new DefaultWebSecurityManager();
//        userRealm().setCredentialsMatcher(credentialsMatcher());
        d.setRealm(userRealm());
        d.setCacheManager(cacheManager());
        return d;
    }
//   缓存管理器，管理缓存
    @Bean
    public EhCacheManager cacheManager(){
        EhCacheManager ehCacheManager=new EhCacheManager();
        // 两种方式配置缓存对象
//        ehCacheManager.setCacheManagerConfigFile("classpath:ehcache.xml");
        CacheManager cacheManager=new CacheManager();
        ehCacheManager.setCacheManager(cacheManager);
        return ehCacheManager;
    }


    @Bean
    public UserRealm userRealm(){
        return new UserRealm();
    }
//    @Bean
//    public HashedCredentialsMatcher credentialsMatcher(){
//        HashedCredentialsMatcher hashedCredentialsMatcher=new HashedCredentialsMatcher();
//        hashedCredentialsMatcher.setHashAlgorithmName("md5");
//        hashedCredentialsMatcher.setHashIterations(1);
//        return hashedCredentialsMatcher;
//    }

    //    PropertyPlaceholderConfigurer用于加载配置文件
//    配置jedis连接池
    @Bean
    public JedisPoolConfig jedisPoolConfig(){
        JedisPoolConfig jedisPoolConfig=new JedisPoolConfig();
        jedisPoolConfig.setMaxIdle(300);
        jedisPoolConfig.setMaxWaitMillis(-1);
        jedisPoolConfig.setTestOnBorrow(true);
        return jedisPoolConfig;
    }

    //    配置redis连接工厂
    @Bean
    public JedisConnectionFactory jedisConnectionFactory(){
        JedisConnectionFactory jedisConnectionFactory=new JedisConnectionFactory();
        jedisConnectionFactory.setPoolConfig(jedisPoolConfig());
        jedisConnectionFactory.setPort(6379);
        jedisConnectionFactory.setHostName("127.0.0.1");
        jedisConnectionFactory.setTimeout(3000);
        return jedisConnectionFactory;
    }
    //    Jedis模板配置
    @Bean
    public RedisTemplate redisTemplate(){
        RedisTemplate redisTemplate=new RedisTemplate();
        redisTemplate.setConnectionFactory(jedisConnectionFactory());
//        如果不配置Serializer，那么存储的时候只能使用String，如果用对象类型存储，那么会提示错误 can't cast to String！
        redisTemplate.setKeySerializer(new StringRedisSerializer());
//        开启事务支持
        redisTemplate.setEnableTransactionSupport(true);
        return redisTemplate;
    }
    @Bean
//    redis工具类
    public RedisUtil redisUtil(){
        return new RedisUtil(redisTemplate());
    }
}
